<?php

function prog_exec($command, $user_to_run_under = "", $dump_to_console = false, $stdout_callback = "", $stderr_callback = "", $echo_dump_prefix = "") {

	if ($command == "") {
		echo "*** function prog_exec: wrong params\n";
		return false;
	}

	$time_start = microtime(1);

	$descriptorspec = array(
		0 => array("pipe", "r"),
		1 => array("pipe", "w"),
		2 => array("pipe", "w")
	);

	if ($user_to_run_under != "") {
		if ($user_to_run_under != posix_getlogin()) {
			$process = proc_open("su - ".$user_to_run_under." -c \"".$command."\"", $descriptorspec, $pipes);
		}
	} else {
		$process = proc_open($command, $descriptorspec, $pipes);
	}

	if (is_resource($process)) {

		// отправляем текст в программу
		// открывать эту строку не стоит - сегодня для этого нет нужны,
		// да и код надо дописать маленько
		//fwrite($pipes[0], $command_through_stdin."\r\n");

		fclose($pipes[0]);

		stream_set_blocking($pipes[1], 0);
		stream_set_blocking($pipes[2], 0);

		$stdout_lines = 0;
		$stderr_lines = 0;
		$stdout_buffer = "";
		$stderr_buffer = "";

		while(!feof($pipes[1]) || !feof($pipes[2])) {
			$read_line = false;
			if (!feof($pipes[1])) {
				$buf = fgets($pipes[1]);

				if (strlen($buf) > 0) {
					$read_line = true;
					$stdout_buffer .= $buf;
			        	$stdout_lines ++;

					if ($dump_to_console == true) {
						if ($echo_dump_prefix != "") {
							echo $echo_dump_prefix." ".$buf;
						} else {
							echo $buf;
						}
					}

					if (function_exists($stdout_callback)) {
						$stdout_callback($buf, $stdout_lines);
					}
				}
			}

			if (!feof($pipes[2])) {
				$buf = fgets($pipes[2]);

				if (strlen($buf) > 0) {
					$read_line = true;
					$stderr_buffer .= $buf;
					$stderr_lines ++;

					if ($dump_to_console == true) {
						if ($echo_dump_prefix != "") {
							echo $echo_dump_prefix." ".$buf;
						} else {
							echo $buf;
						}
					}

					if (function_exists($stderr_callback)) {
						$stderr_callback($buf, $stderr_lines);
		                	}
				}
			}

			if (!$read_line) {
				usleep(100000);  // 0.1 seconds
			}
		}

		fclose($pipes[1]);
		fclose($pipes[2]);

		$return_value = proc_close($process);
	}

	$time_end = microtime(1);
	$time = $time_end - $time_start;

	return array(
		"stdout" => array(
			"data" => $stdout_buffer,
			"lines" => $stdout_lines
		),
		"stderr" => array(
			"data" => $stderr_buffer,
			"lines" => $stderr_lines
		),
		"time" => $time,
		"return_value" => $return_value
	);

}

?>
